<?php
namespace Framework;


class Module
{
    //应用组件
    public $_components = [];

    public $defaultRoute = 'index';

    public $controllerNamespace;

    public $module = [];

    private $_module  = [];

    public function __construct()
    {
        $this->init();
    }

    public function init()
    {
        if ($this->controllerNamespace === null) {
            $class = get_class($this);
            if (($pos = strrpos($class, '\\')) !== false) {
                $this->controllerNamespace = substr($class, 0, $pos) . '\\controllers';
            }
        }
    }

    public function getComponent($name){
    	if( !is_object($this->_components[$name]) ){
    		$className = $this->_components[$name]['_class'];

    		if( $name == 'request' ){
    			//request组件暂时特殊处理
    			$component = Http\Request::createFromGlobals();


    		}else{
	    		if( method_exists($className, 'getInstance') ){
	    			$component = $className::getInstance();
	    		}else{
	    			$component = new $className();
	    		}
    		}
    		
    		$this->_components[$name] = $component;
    	}


    	//返回实例化后的组件单例
    	return $this->_components[$name];
    }

    public function regComponents($components)
    {
        foreach ($this->coreComponents() as $id => $component) {
            if (!isset($components[$id])) {
                $components[$id] = $component;
            } elseif (is_array($components[$id]) && !isset($components[$id]['class'])) {
               $components[$id]['_class'] = $component['_class'];
            }
        }
        return $components;
    }

    //运行action
    public function runAction($route, $params)
    {
        $parts = $this->createController($route);

        if( !is_array($parts) ){
            throw new \Exception("请求无法被解析 $route");
        }

        list($controller, $actionID) = $parts;
        return $controller->runAction($actionID, $params);
    }

    //创建控制器
    public function createController($route)
    {
        $route = trim($route, '/');
        if ($route === '') {
            $route = $this->defaultRoute;
        }

        //安全过滤
        $route = trim($route, '/');
        if (strpos($route, '//') !== false) {
            return false;
        }

        //截取出Url的第一段
        if (strpos($route, '/') !== false) {
            list($id, $route) = explode('/', $route, 2);
        } else {
            $id = $route;
            $route = '';
        }

        //controllerMap 判断


        //子模块判断
        $module = $this->getModule($id);
        if ($module !== null) {
            // exit('in module');
            return $module->createController($route);
        }

        // 直接创建控制器
        $controller = $this->createControllerByID($id);

        return $controller === null ? false : [$controller, $route];
    }

    public function createControllerByID($id)
    {
        $className = $id;

        //控制器id格式化(大驼峰) + controller后缀
        $className = preg_replace_callback('%-([a-z0-9_])%i', function ($matches) {
                return ucfirst($matches[1]);
            }, ucfirst($className)) . 'Controller';

        //类名组装命名空间
        $className = ltrim($this->controllerNamespace . '\\' . $className, '\\');


        // 判断控制器类是否存在
        if (strpos($className, '-') !== false || !class_exists($className)) {
            return null;
        }


        //is_subclass_of 判断控制器是否继承了基类
        if (is_subclass_of($className, Controller::class)) {
            $controller = new $className();
        }else{
            throw new \Exception('控制器必须集成 \\Framework\\Controller in '.$className);
        }

        return get_class($controller) === $className ? $controller : null;
    }


    public function getModule($id)
    {
        if (($pos = strpos($id, '/')) !== false) {
            throw new \Exception("module id 出现了意外的字符");   
        }

        if( !isset($this->module[$id]) ){
            return null;
        }

        if( isset($this->_module[$id]) ){
            return $this->_module[$id];
        }

        $moduleClass = $this->module[$id]['class'];
        if( !class_exists($moduleClass) ){
            throw new \Exception("实例化 {$id} 模块时找不到:".$moduleClass);
        }


        $module = new $moduleClass();
        $this->_module[$id] = $module;

        // echo get_called_class();exit;

        return $module;
    }



    public function __get($name){
        if( in_array($name, array_keys($this->_components)) ){
            return $this->getComponent($name);
        }

        throw new \Exception('获取未知属性 : ' . get_class($this) . '::' . $name);
    }
}